// Events
taxi.FROM_CHANGE_EVENT = "fromChangeEvent";
taxi.TO_CHANGE_EVENT = "toChangeEvent";
taxi.STATE_CHANGE_EVENT = "stateChangeEvent";
taxi.ROUTE_CHANGE_EVENT = "routeChangeEvent";
taxi.FARE_RESOLVED_EVENT = "fareResolvedEvent";
// Geocoding constants
taxi.CONTEXT_RADIUS = 30000;
taxi.GEO_TIMEOUT = 20000;

// Both addresses not set yet
taxi.STATE_POPULATING = 1;
//Routes resolved
taxi.STATE_ROUTE_RETRIEVING = 2;
// Routes resolved
taxi.STATE_ROUTE_RESOLVED = 3;
// Potential mates found
taxi.STATE_ROUTE_SHARING = 4;

taxi.TaxiEngine = function(_mapViewer, _geocoder) {
	this._remoteEngine = new taxi.RemoteEngine();
	this._mapViewer = _mapViewer;
	this._geocoder = _geocoder;
	this._routeManager = new taxi.RouteManager();
	this._partnerManager = new taxi.PartnerManager(this._remoteEngine);
	this._currentUser = undefined;
	this._currentPosition = undefined;
	this._detectedPosition = undefined;
	this._currentState = undefined;
	this._fareCalculator = new taxi.SFFareCalculator(this._remoteEngine);
}

taxi.TaxiEngine.prototype.init = function() {
	this._currentUser = undefined;
	this._currentPosition = undefined;
	this._detectedPosition = undefined;
	this._currentState = undefined;
	this.setCurrentState(taxi.STATE_POPULATING);
}

//
taxi.TaxiEngine.prototype.toString = function() {
	console.log(" Taxi Engine v.0");
}
taxi.TaxiEngine.prototype.getCurrentRoute = function() {
	return this._routeManager.getCurrentRoute();
}
taxi.TaxiEngine.prototype.setCurrentRoute = function(currentRoute) {
	this._routeManager.setCurrentRoute(currentRoute);
	this._fareCalculator.retrieveFare(this._routeManager.getCurrentRoute(),
			new taxi.ResultHandler(this, this.fareSuccessHandler),
			new taxi.ResultHandler(this, this.fareFailHandler));
	$(this).trigger(taxi.ROUTE_CHANGE_EVENT, this._routeManager.getCurrentRoute());
}
taxi.TaxiEngine.prototype.getRouteManager = function() {
	return this._routeManager;
}
taxi.TaxiEngine.prototype.setCurrentState = function(state) {
	if (this._currentState != state) {
		this._currentState = state;
		$(this).trigger(taxi.STATE_CHANGE_EVENT, this._currentState);
	}
}
taxi.TaxiEngine.prototype.geocodeFromAddress = function(addressString) {
	var self = this;
	if (addressString == undefined || addressString == "") {
		self._routeManager.setFromAddress(undefined);
		self.centerView();
	} else {
		var context = {};
		if ((self._routeManager.toAddress != undefined)
				&& (self._routeManager.toAddress.getLatLon() != undefined)) {
			context.location = self._routeManager.toAddress.getLatLon();
		}
		this._geocoder.consolidateAddress(addressString, context, function(
				newAddress) {
			self._routeManager.setFromAddress.call(self._routeManager,
					newAddress);
			self.centerView.call(self);
		});
	}
}

taxi.TaxiEngine.prototype.geocodeToAddress = function(addressString) {
	var self = this;
	if (addressString == undefined || addressString == "") {
		self._routeManager.setToAddress(undefined);
		self.centerView();
	} else {
		var context = {};
		if ((self._routeManager.fromAddress != undefined)
				&& (self._routeManager.fromAddress.getLatLon() != undefined)) {
			context.location = self._routeManager.fromAddress.getLatLon();
		}
		this._geocoder.consolidateAddress(addressString, context, function(
				newAddress) {
			self._routeManager.setToAddress
					.call(self._routeManager, newAddress);
			self.centerView.call(self);
		});
	}
}

/**
 * Function used to initialize the client position. Creates an Address object
 * and registers change handlers to update the related data input form
 */
taxi.TaxiEngine.prototype.setCurrentPosition = function(latLon, handler) {
	this._currentPosition = new taxi.Address( {
		lat : latLon[0],
		lon : latLon[1]
	});
	//
	var curPos = this._currentPosition;
	var self = this;
	this.resolveAddress(this._currentPosition, new taxi.ResultHandler(this,
			function(val) {
				self._currentPosition.addressString = val;
				handler.invoke( [ self._currentPosition ]);
			}));
}
taxi.TaxiEngine.prototype.resetRoute = function() {
	this.setCurrentRoute(undefined);
	this.setCurrentState(taxi.STATE_POPULATING);
	this._mapViewer.clearRoute();
}
taxi.TaxiEngine.prototype.checkRouteResolution = function() {
	if (this._routeManager.fromAddress != undefined
			&& this._routeManager.toAddress != undefined) {
		// Check if we really need to request the route
		/*
		 * var oldRoute = (this._currentRoute == undefined) ||
		 * !this._routeManager.fromAddress.sameCoords(
		 * this._currentRoute.requestedFromCoords ) ||
		 * !this._routeManager.toAddress.sameCoords(
		 * this._currentRoute.requestedToCoords ); if(oldRoute){
		 */
		this.setCurrentState(taxi.STATE_ROUTE_RETRIEVING);
		this._mapViewer.resolveRoute(this._routeManager.fromAddress,
				this._routeManager.toAddress, new taxi.ResultHandler(this,
						this.routeResolvedHandler));
		// }
	}
}

taxi.TaxiEngine.prototype.shareCurrentRoute = function(){
	this.setCurrentState(taxi.STATE_ROUTE_SHARING);
	//
	this._partnerManager.retrievePartners(this._routeManager.getCurrentRoute());
	
}

taxi.TaxiEngine.prototype.fareSuccessHandler = function(result) {
	console.debug("Fare for route received:");
	console.dir(result);
	$(this).trigger(taxi.FARE_RESOLVED_EVENT, result);
}

taxi.TaxiEngine.prototype.fareFailHandler = function(result) {
	alert(result);
}

taxi.TaxiEngine.prototype.routeResolvedHandler = function(currentRoute) {
	this.setCurrentRoute(currentRoute);
	this.setCurrentState(taxi.STATE_ROUTE_RESOLVED);
}

/**
 * Function to retrieve an address string from an Address object with populated
 * lat and lon's
 */
taxi.TaxiEngine.prototype.resolveAddress = function(address, handler) {
	this._geocoder.resolveAddress(address.getLatLon(), function(result) {
		handler.invoke( [ result ]);
	});
}

// Display related
taxi.TaxiEngine.prototype.drawFromLocation = function() {
	this._mapViewer.drawFromLocation(this._routeManager.fromAddress);
}
taxi.TaxiEngine.prototype.drawToLocation = function() {
	this._mapViewer.drawToLocation(this._routeManager.toAddress);
}
taxi.TaxiEngine.prototype.clearFromLocation = function() {
	this._mapViewer.clearFromLocation();
}
taxi.TaxiEngine.prototype.clearToLocation = function() {
	this._mapViewer.clearToLocation();
}

taxi.TaxiEngine.prototype.centerView = function() {
	if (this._routeManager.fromAddress != undefined
			&& this._routeManager.toAddress != undefined) {
		// Both set
		this._mapViewer.setBounds(this._routeManager.fromAddress,
				this._routeManager.toAddress);
	} else if (this._routeManager.fromAddress != undefined) {
		// From set
		this._mapViewer.centerTo(this._routeManager.fromAddress);
	} else if (this._routeManager.toAddress != undefined) {
		// To set
		this._mapViewer.centerTo(this.toAddress.fromAddress);
	}
}